package com.cheer.manager;

import com.cheer.dao.AccountDao;
import com.cheer.dao.AccountUniqueSupportDao;
import com.cheer.dto.AccountDTO;
import com.cheer.entity.Account;
import com.cheer.entity.AccountUniqueSupport;
import com.cheer.exception.ServiceException;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author cheer
 */
@Service
public class AccountManager {

    public static final String INITIAL_PASSWORD = "000000";

    @Autowired
    private AccountDao accountDao;

    @Autowired
    private AccountUniqueSupportDao accountUniqueSupportDao;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 重置密码
     *
     * @param accountId 账号Id
     */
    public void resetPassword(Long accountId) {
        Account account = new Account();
        account.setId(accountId);
        account.setPassword(passwordEncoder.encode(INITIAL_PASSWORD));
        accountDao.updateById(account);
    }

    /**
     * 删除账户
     *
     * @param accountIds 账号Id集体
     */
    @Transactional
    public void deleteByIds(List<Long> accountIds) {
        List<Account> accounts = accountDao.selectBatchIds(accountIds);
        if (CollectionUtils.isEmpty(accounts)) {
            return;
        }
        Set<String> accountNames = new HashSet<>();
        for (Account account : accounts) {
            accountNames.addAll(Lists.newArrayList(account.getPhone(), account.getBackupAccount()));
        }
        accountDao.deleteBatchIds(accountIds);
        if (CollectionUtils.isNotEmpty(accountNames)) {
            accountUniqueSupportDao.deleteBatchIds(accountNames);
        }
    }

    /**
     * 新增账户
     *
     * @param accountDTO 账户信息
     */
    @Transactional
    public Long saveAccount(AccountDTO accountDTO) {
        // 校验账号唯一
        checkAccountUnique(Sets.newHashSet(accountDTO.getPhone(), accountDTO.getBackupAccount()));
        // 设置默认密码
        if (StringUtils.isBlank(accountDTO.getPassword())) {
            accountDTO.setPassword(INITIAL_PASSWORD);
        }
        // 添加账号
        Account account = accountDTO.build(passwordEncoder);
        accountDao.insert(account);
        return account.getId();
    }

    /**
     * 查询账户
     *
     * @param account 账号信息
     */
    public Account getByAccount(String account) {
        List<Account> accounts = accountDao.listByAccount(account);
        Optional<Account> optional = accounts.stream()
                .filter(item -> !item.getLocked())
                .findFirst();
        return optional.orElse(null);
    }

    /**
     * 修改密码
     *
     * @param accountId 账号Id
     * @param password  密码
     */
    public void updatePassword(Long accountId, String password) {
        Account account = new Account();
        account.setId(accountId);
        account.setPassword(passwordEncoder.encode(password));
        accountDao.updateById(account);
    }

    /**
     * 锁定账号
     *
     * @param accountId 账号Id
     */
    @Transactional
    public void lockAccount(Long accountId) {
        Account account = accountDao.selectById(accountId);
        if (account == null) {
            return;
        }
        Set<String> accountNames = Sets.newHashSet(account.getPhone(), account.getBackupAccount());
        accountUniqueSupportDao.deleteBatchIds(accountNames);
        Account lockedAccount = new Account();
        lockedAccount.setId(accountId);
        lockedAccount.setLocked(true);
        accountDao.updateById(lockedAccount);
    }

    /**
     * 校验密码
     *
     * @param accountId 账户Id
     * @param password  密码
     */
    public Account checkPassword(Long accountId, String password) {
        Account account = accountDao.selectById(accountId);
        if (account == null || account.getLocked()) {
            throw new ServiceException("账号已失效");
        }
        if (!passwordEncoder.matches(password, account.getPassword())) {
            throw new ServiceException("输入密码不正确");
        }
        return account;
    }

    /**
     * 修改手机号
     *
     * @param phone   手机号
     * @param account 当前账户信息
     */
    public void updatePhone(String phone, Account account) {
        // 账号无修改直接返回
        if (StringUtils.equals(phone, account.getPhone())) {
            return;
        }
        // 修改为备用账号直接修改不用校验
        if (StringUtils.equals(phone, account.getBackupAccount())) {
            Account update = new Account();
            update.setId(account.getId());
            update.setPhone(phone);
            accountDao.updateById(update);
            accountUniqueSupportDao.deleteById(account.getPhone());
            return;
        }
        // 修改为新账号需要检查账号唯一性
        checkAccountUnique(Sets.newHashSet(phone));
        Account update = new Account();
        update.setId(account.getId());
        update.setPhone(phone);
        accountDao.updateById(update);
        // 删除旧账号的唯一标识
        if (!StringUtils.equals(account.getPhone(), account.getBackupAccount())) {
            accountUniqueSupportDao.deleteById(account.getPhone());
        }
    }

    /**
     * 修改备用账号
     *
     * @param backupAccount 备用账号
     * @param account       当前账户信息
     */
    public void updateBackAccount(String backupAccount, Account account) {
        // 账号无修改直接返回
        if (StringUtils.equals(backupAccount, account.getBackupAccount())) {
            return;
        }
        // 修改为手机号直接修改不用校验
        if (StringUtils.equals(backupAccount, account.getPhone())) {
            Account update = new Account();
            update.setId(account.getId());
            update.setBackupAccount(backupAccount);
            accountDao.updateById(update);
            accountUniqueSupportDao.deleteById(account.getPhone());
            return;
        }
        // 修改为新账号需要检查账号唯一性
        checkAccountUnique(Sets.newHashSet(backupAccount));
        Account update = new Account();
        update.setId(account.getId());
        update.setBackupAccount(backupAccount);
        accountDao.updateById(update);
        // 删除旧账号的唯一标识
        if (!StringUtils.equals(account.getPhone(), account.getBackupAccount())) {
            accountUniqueSupportDao.deleteById(account.getBackupAccount());
        }
    }

    /**
     * 校验账号唯一
     *
     * @param accounts 账号集合
     */
    private void checkAccountUnique(Set<String> accounts) {
        accounts = accounts.stream().filter(StringUtils::isNotBlank).collect(Collectors.toSet());
        List<AccountUniqueSupport> uniqueAccounts = accountUniqueSupportDao.selectBatchIds(accounts);
        if (CollectionUtils.isNotEmpty(uniqueAccounts)) {
            throw new ServiceException("手机号或备用账号已存在");
        }
        uniqueAccounts = accounts.stream()
                .map(account -> {
                    AccountUniqueSupport uniqueAccount = new AccountUniqueSupport();
                    uniqueAccount.setAccount(account);
                    return uniqueAccount;
                })
                .collect(Collectors.toList());
        try {
            accountUniqueSupportDao.insertBatch(uniqueAccounts);
        } catch (DuplicateKeyException e) {
            throw new ServiceException("手机号或备用账号已存在");
        }
    }
}
